<html>
	<head>
		<!-- Update title -->
		<title>OpenGL in Cinder: Getting Started</title>

   		<!-- master stylesheet - these links will be replaced when compiled -->
		<link rel="stylesheet" href="../../_assets/css/foundation.css">
		<link rel="stylesheet" href="../../_assets/css/prism.css">
		<link rel="stylesheet" href="../../_assets/css/style.css">
		<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700' rel='stylesheet' type='text/css'>
	</head>

<body id="guide-contents" >

<h1>OpenGL in Cinder</h1>
<a id="getting_started"></a>
<h2>Getting Started</h2>
<p></p>

<p>Let's begin by looking at a minimal OpenGL application written with Cinder. This barebones app simply draws a blank, black window:</p>

<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"

using namespace ci;
using namespace ci::app;

class BasicApp : public App {
  public:
	void draw() override;
};

void BasicApp::draw()
{
	gl::clear();
}

CINDER_APP( BasicApp, RendererGl )</code></pre>
</div>
<div class="col">
<img src="images/blank.png" class="shadow" />
</div>
</div>

<br />

<p>In order to use OpenGL, a Cinder app instantiates <ci dox="app::RendererGl">app::RendererGl <span class="plain">UNSTYLE</span></ci> using the <code>CINDER_APP</code> macro. The most straightforward way to start to use Cinder's OpenGL API is to <code>#include "cinder/gl/gl.h"</code>. While this does not include all of Cinder's OpenGL headers, it does include some of the commonly used ones.</p>

<a id="convenience_functions"></a>
<h3>Convenience Functions</h3>
<p>Often you're more interested in ease of implementation than performance. Cinder's <ci>ci::gl</ci> convenience functions are for this purpose. Let's look at how to use them to draw a filled circle. A modified version of the previous example's <code>draw()</code> method follows:<p>

<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
void BasicApp::draw()
{
	gl::clear();
	gl::drawSolidCircle( getWindowCenter(), 200 );
}
</code></pre>
</div>
<div class="col">
<img src="images/circle.png" class="shadow" />
</div>
</div>

<p>We're making use of the <ci>gl::drawSolidCircle()</ci> function, which takes a <ci>vec2</ci> offset and a radius. This short example also highlights the fact that by default <ci>app::RendererGl</ci> sets up a coordinate system that matches the <ci>app::Window</ci> 1:1 in pixels. Later we'll look at how to manipulate the coordinate system.</p>

<p>Let's make another modification to the <code>draw()</code> method:</p>
<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
void BasicApp::draw()
{
	gl::clear();
	vec2 center = getWindowCenter();
	float r = 100;

	gl::color( Color( 1, 0, 0 ) ); // red
	gl::drawSolidCircle( center + vec2( -r, r ), r );
	gl::color( Color( 0, 1, 0 ) ); // green
	gl::drawSolidCircle( center + vec2( r, r ), r );
	gl::color( Color( 0, 0, 1 ) ); // blue
	gl::drawSolidCircle( center + vec2( 0, -0.73 * r ), r );
}
</code></pre>
</div>
<div class="col">
<img src="images/rgb_circles.png" class="shadow" />
</div>
</div>

<p>The snippet above highlights the <ci>gl::color()</ci> method. This sets a global current color, which the convenience methods make use of.</p>

<!-- TRANSFORMATIONS
-->
<a id="transformations"></a>
<h2>Transformations</h2>

<p>Traditionally in computer graphics, transformations (operations like translation, scale and rotation) are implemented using 4x4 matrices. Cinder's <code>Model</code> matrix is a global transformation which is applied to any draw call. Routines like <ci>gl::translate()</ci>, <ci>gl::scale()</ci> and <ci>gl::rotate()</ci> manipulate the active <code>Model</code> matrix.</p>

<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
void BasicApp::draw()
{
	gl::clear();
	// reset the matrices
	gl::setMatricesWindow( getWindowSize() );

	// move to the horizontal window center, down 75
	gl::translate( getWindowCenter().x, 75 );
	gl::color( Color( 1, 0, 0 ) );
	gl::drawSolidCircle( vec2( 0 ), 70 );

	// move down 150 pixels
	gl::translate( 0, 150 );
	gl::color( Color( 1, 1, 0 ) );
	gl::drawSolidCircle( vec2( 0 ), 70 );
	
	// move down another 150 pixels
	gl::translate( 0, 150 );
	gl::color( Color( 0, 1, 0 ) );
	gl::drawSolidCircle( vec2( 0 ), 70 );
}
</code></pre>
</div>
<div class="col">
<img src="images/basic_transformations.png" class="shadow" />
</div>
</div>

<p>There's a couple of things to notice in this code, the first being the call to <ci>gl::setMatricesWindow()</ci>. This sets the <code>Model</code> matrix to Cinder's default, window-aligned configuration when passed the Window's current size (via <ci>getWindowSize()</ci>). If we did not call this, we would keep translating the <code>Model</code> matrix indefinitely, and our circles would quickly be too far down to see. This is because the effects of <ci>gl::translate()</ci> <em>et al.</em> are cumulative, meaning the operation is appended to the current <code>Model</code> matrix rather than replacing it. In the case above, a call to <code>gl::translate( 0, 150 )</code> translates the current <code>Model</code> matrix 150 units vertically; note it <strong>does not</strong> <em>set</em> the translation to <code>( 0, 150 )</code>.</p>

<p>Also key is to note that we draw the circles with an offset of <code>(0,0)</code> now, since we are relying on the <code>Model</code> matrix manipulated by <ci>gl::translate()</ci> to position them.</p>

<p>For many use cases, it can be convenient to preserve, manipulate and then restore the <code>Model</code> matrix. Cinder makes this simple by using a stack of matrices, coupled with the routines <ci>gl::pushModelMatrix()</ci> to push and preserve the <code>Model</code> matrix, and <ci>gl::popModelMatrix()</ci> to restore it. Let's take a look at an example of how this can be useful.</p>

<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
void BasicApp::draw()
{
	gl::clear();

	// preserve the default Model matrix
	gl::pushModelMatrix();
	// move to the window center
	gl::translate( getWindowCenter() );

	int numCircles = 16;
	float radius = getWindowHeight() / 2 - 30;
	
	for( int c = 0; c < numCircles; ++c ) {
		float rel = c / (float)numCircles;
		float angle = rel * M_PI * 2;
		vec2 offset( cos( angle ), sin( angle ) ); 
		
		// preserve the Model matrix
		gl::pushModelMatrix();
		// move to the correct position
		gl::translate( offset * radius );
		// set the color using HSV color
		gl::color( Color( CM_HSV, rel, 1, 1 ) );
		// draw a circle relative to Model matrix
		gl::drawStrokedCircle( vec2(), 30 );
		// restore the Model matrix
		gl::popModelMatrix();
	}

	// draw a white circle at window center
	gl::color( Color( 1, 1, 1 ) );
	gl::drawSolidCircle( vec2(), 15 );

	// restore the default Model matrix
	gl::popModelMatrix();
}
</code></pre>
</div>
<div class="col">
<img src="images/circle_transformations.png" class="shadow" />
</div>
</div>

<p>In this example, we preserve the default <code>Model</code> matrix by calling <ci>gl::pushModelMatrix()</ci> at the start of <code>draw()</code>, and calling <ci>gl::popModelMatrix()</ci> at the end. Note that we no longer need the call to <ci>gl::setMatricesWindow()</ci> as a result. Next, we translate to <ci>getWindowCenter()</ci>, so all subsequent draw calls are relative to the window's center. Then inside of a for-loop, we draw a series of circular outlines arranged in a circle whose radius is based on the height of the window. For each, we first do some basic trigonometry to determine the offset. Then we save a copy of the current <code>Model</code> matrix and translate by this offset. Recall that because these transformations are cumulative, this translation is relative to the window center, due to our earlier call to <ci>gl::translate()</ci>. Next we set the color using HSV color and draw a circle relative to the current <code>Model</code> matrix. We then restore the matrix (setting it to be the window center once again) using <ci>gl::popModelMatrix()</ci>. Finally, we draw a white circle at the window center and restore the matrix to its value when first entered <code>draw()</code>.</p>

<p>If you're wondering if we could achieve the same thing simply by passing <code>offset * radius</code> as the first parameter to <ci>gl::drawStrokedCircle()</ci>, you're correct. Let's look at an example which could not be achieved without using transformations. Here we'll use the <ci dox="ci::gl::scale(float,float)">gl::scale()</ci> and <ci dox="ci::gl::rotate(float)">gl::rotate()</ci> functions.</p>

<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
void BasicApp::draw()
{
	gl::clear();

	// preserve the default Model matrix
	gl::pushModelMatrix();
	// move to the window center
	gl::translate( getWindowCenter() );

	int numCircles = 32;
	float radius = getWindowHeight() / 2 - 30;
	
	for( int c = 0; c < numCircles; ++c ) {
		float rel = c / (float)numCircles;
		float angle = rel * M_PI * 2;
		vec2 offset( cos( angle ), sin( angle ) );
		
		// preserve the Model matrix
		gl::pushModelMatrix();
		// move to the correct position
		gl::translate( offset * radius );
		// rotate by current angle
		gl::rotate( angle );
		// non-uniform scale
		gl::scale( 8, 0.25f );
		// set the color using HSV color
		gl::color( Color( CM_HSV, rel, 1, 1 ) );
		// draw a circle based on the current Model matrix
		gl::drawSolidCircle( vec2(), 20 );
		// restore the Model matrix
		gl::popModelMatrix();
	}

	// restore the default Model matrix
	gl::popModelMatrix();
}
</code></pre>
</div>
<div class="col">
<img src="images/multi_transformations.png" class="shadow" />
</div>
</div>

<p>In this example, we demonstrate a couple of new things. For each circle, we start by scaling it non-uniformly, making it 8 times as wide and &frac14; as tall, by passing <code>( 8, 0.25f )</code> to <ci dox="ci::gl::scale(float,float)">gl::scale()</ci>. We also <ci dox="ci::gl::rotate(float)">gl::rotate()</ci> each circle (now oval) by an angle that matches its position in the circular arrangement. Last, we move each oval to its position in the circle using <ci>gl::translate()</ci>. Note however that we make these calls in the reverse order to how they occur conceptually. Specifically, we call <ci>gl::translate()</ci>, followed by <ci dox="ci::gl::rotate(float)">gl::rotate()</ci>, followed by <ci dox="ci::gl::scale(float,float)">gl::scale()</ci>, but the effect we achieve is the reverse - scaling, then rotation, then translation. This reversed order of operations is typical for graphics APIs and will grow comfortable for you if it's not already. And of course all of this points to the fact that the order of operations does indeed matter:</p>

<div class="cols-2">
<div class="col">
<pre><code class="lang-cpp">
void BasicApp::draw()
{
	&hellip;	
	for( int c = 0; c < numCircles; ++c ) {
		&hellip;
		gl::translate( offset * radius );
		// reversed scale & rotate
		gl::scale( 8, 0.25f );
		gl::rotate( angle );
		gl::drawSolidCircle( vec2(), 20 );
		&hellip;
	}
	&hellip;
}
</code></pre>
</div>
<div class="col">
<img src="images/multi_transformations_wrong.png" class="shadow" />
</div>
</div>

<p>Here we've only swapped the order of the calls to <ci dox="ci::gl::scale(float,float)">gl::scale()</ci> and <ci dox="ci::gl::rotate(float)">gl::rotate()</ci>, and it's obvious the order matters quite a bit. Consider what we're doing conceptually, keeping in mind that the operations are applied "in reverse" - they should be read from bottom-to-top relative to the draw call. First, we rotate by <em>angle</em>. However rotating a circle results in the same circle, so this achieves no effect. Next, we apply our non-uniform scale, creating an oval, and then finally we position the oval in the circular arrangement.</p>

<p>In the next section we'll look at how to take these concepts into 3D.</p>

<script src="../../_assets/js/prism.js" type="text/javascript"></script>
</body>
</html>